#include "stdafx.h"
#include "CppUnitTest.h"

#include <vex.tests/mstest/log_message.h>
#include <vex.tests/mstest/crt_mem_check.h>
#include <vex.tests/mstest/tests.range/range_archetype.h>
// pulls in all concepts:
#include <vex/iterable/concept/range_concepts.h>
#include <vex/iterable/stl_interop.h>
#include <vex/iterable/stl_interop/tti.h>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

//namespace vex { namespace iterable { namespace stl_interop {
//    template<class TContainer> struct lazy_enable_if_is_container : public boost::lazy_enable_if_c<
//        is_container<TContainer>::value,
//        make_range_from_container<TContainer>
//    > {};
//}}}

namespace tests {	namespace range_stl_interop_meta {

    using namespace boost::assign;

    namespace vi = vex::iterable;

    TEST_CLASS(range_stl_interop_meta)
    {
        BEGIN_TEST_CLASS_ATTRIBUTE()
            TEST_CLASS_ATTRIBUTE(L"Module", L"tests.range.stl_interop_meta")
        END_TEST_CLASS_ATTRIBUTE();
    public:
        TEST_METHOD(has_const_member_function_begin_is_true_for_vector)
        {
            Assert::IsTrue(vex::iterable::stl_interop::has_member_function_begin<
                std::vector<int>::const_iterator (std::vector<int>::*)() const
            >::value);

            Assert::IsTrue(vex::iterable::stl_interop::has_member_function_begin<
                const std::vector<int>, std::vector<int>::const_iterator
            >::value);
        }

        TEST_METHOD(has_type_const_iterator_is_true_for_map)
        {
            Assert::IsTrue(vex::iterable::stl_interop::has_type_const_iterator< std::map<int, int> >::value);
        }

        TEST_METHOD(has_const_member_function_begin_is_true_for_map)
        {
            Assert::IsTrue(vex::iterable::stl_interop::has_member_function_begin<
                std::map<int, int>::const_iterator (std::map<int, int>::*)() const
            >::value);

            Assert::IsTrue(vex::iterable::stl_interop::has_member_function_begin<
                const std::map<int, int>, std::map<int, int>::const_iterator
            >::value);
        }

        TEST_METHOD(has_member_function_begin_is_true_for_map)
        {
            Assert::IsTrue(vex::iterable::stl_interop::has_member_function_begin<
                std::map<int, int>::iterator (std::map<int, int>::*)()
            >::value);

            Assert::IsTrue(vex::iterable::stl_interop::has_member_function_begin<
                std::map<int, int>, std::map<int, int>::iterator
            >::value);
        }

        TEST_METHOD(has_const_member_functions_begin_and_end_is_true_for_map)
        {
            // ok, this fails with MSVC11, begin is defined in the base class...
            Assert::IsTrue(vex::iterable::stl_interop::has_const_member_functions_begin_and_end<
                std::map<int, int>, vex::iterable::stl_interop::has_type_const_iterator< std::map<int, int> >::value
            >::value);
        }

        TEST_METHOD(is_container_is_true_for_map)
        {
            Assert::IsTrue(vex::iterable::stl_interop::is_container< std::map<int, int> >::value);
        }

        TEST_METHOD(has_type_const_iterator_is_true_for_set)
        {
            Assert::IsTrue(vex::iterable::stl_interop::has_type_const_iterator< std::set<int> >::value);
        }

        TEST_METHOD(has_const_member_functions_begin_and_end_is_true_for_set)
        {
            Assert::IsTrue(vex::iterable::stl_interop::has_const_member_functions_begin_and_end< 
                std::set<int>, 
                true/*vex::iterable::stl_interop::has_type_const_iterator< std::set<int> >::value*/
            >::value);
        }

        TEST_METHOD(is_container_is_true_for_set)
        {
            Assert::IsTrue(vex::iterable::stl_interop::is_container< std::set<int> >::value);
        }

        TEST_METHOD(is_container_is_true_for_container_like_types_and_false_otherwise)
        {
            Assert::IsFalse(vex::iterable::stl_interop::is_container< int >::value);
            Assert::IsFalse(vex::iterable::stl_interop::is_container< int* >::value);
            Assert::IsFalse(vex::iterable::stl_interop::is_container< int (int) >::value);
            
            Assert::IsTrue(vex::iterable::stl_interop::is_container< std::vector<int> >::value);
            Assert::IsTrue(vex::iterable::stl_interop::is_container< std::list<int> >::value);

#if _MSC_VER == 1800 && BOOST_VERSION == 105500
#pragma message(__FILE__ " boost::container::slist does not compile with boost 105500 and MSC 1800")
#else
            Assert::IsTrue(vex::iterable::stl_interop::is_container< boost::container::slist<int> >::value);
#endif
            typedef std::vector<int> vec_t;
            Assert::IsTrue(vex::iterable::stl_interop::is_container< boost::iterator_range< vec_t::iterator > >::value);
            Assert::IsTrue(vex::iterable::stl_interop::is_container< boost::iterator_range< vec_t::const_iterator > >::value);

            Assert::IsTrue(vex::iterable::stl_interop::is_container< std::vector<int>& >::value);
            Assert::IsTrue(vex::iterable::stl_interop::is_container< std::list<int> const& >::value);
#if _MSC_VER == 1800 && BOOST_VERSION == 105500
#pragma message(__FILE__ " boost::container::slist does not compile with boost 105500 and MSC 1800")
#else
            Assert::IsTrue(vex::iterable::stl_interop::is_container< const boost::container::slist<int> >::value);
#endif
            typedef std::vector<int> vec_t;
            Assert::IsTrue(vex::iterable::stl_interop::is_container< boost::iterator_range< vec_t::iterator >& >::value);
            Assert::IsTrue(vex::iterable::stl_interop::is_container< boost::iterator_range< vec_t::const_iterator>const&  >::value);

            Assert::IsFalse(vex::iterable::stl_interop::is_container< range_archetype<> >::value);
            Assert::IsFalse(vex::iterable::stl_interop::is_container< range_archetype<vex::iterable::random_access_tag, int> >::value);
        }

        TEST_METHOD(has_type_iterator_category_is_true_for_iterators_and_false_otherwise)
        {
            Assert::IsFalse(vex::iterable::stl_interop::has_type_iterator_category< int >::value);
            Assert::IsFalse(vex::iterable::stl_interop::has_type_iterator_category< int* >::value);
            Assert::IsFalse(vex::iterable::stl_interop::has_type_iterator_category< int(int) >::value);
            Assert::IsTrue(vex::iterable::stl_interop::has_type_iterator_category< std::vector<int>::iterator >::value);
            Assert::IsTrue(vex::iterable::stl_interop::has_type_iterator_category< std::list<int>::iterator >::value);
            typedef std::vector<int> vec_t;
            Assert::IsTrue(vex::iterable::stl_interop::has_type_iterator_category<
                boost::iterator_range< vec_t::iterator >::iterator
            >::value);
            Assert::IsTrue(vex::iterable::stl_interop::has_type_iterator_category<
                boost::iterator_range< vec_t::const_iterator >::const_iterator
            >::value);
            Assert::IsFalse(vex::iterable::stl_interop::has_type_iterator_category< range_archetype<> >::value);
            Assert::IsFalse(vex::iterable::stl_interop::has_type_iterator_category< range_archetype<vex::iterable::random_access_tag, int> >::value);
        }

        TEST_METHOD(has_type_iterator_category_is_true_for_iterators_and_false_otherwise_boost_1_55_msc_1800)
        {
#if _MSC_VER == 1800 && BOOST_VERSION == 105500
#pragma message(__FILE__ " boost::container::slist does not compile with boost 105500 and MSC 1800")
            Assert::Fail(wlog_message()
                << __FILE__
                << L" boost::container::slist does not compile with boost 105500 and MSC 1800"
                | as_string);
#else
            Assert::IsTrue(vex::iterable::stl_interop::has_type_iterator_category< boost::container::slist<int>::iterator >::value);
#endif
        }

        TEST_METHOD(is_range_is_true_for_ranges_and_false_otherwise)
        {
            Assert::IsFalse(vex::iterable::is_range< std::vector<int> >::value);
            Assert::IsFalse(vex::iterable::is_range< std::list<int> >::value);
            Assert::IsTrue(vex::iterable::is_range< range_archetype<> >::value);
            Assert::IsTrue(vex::iterable::is_range< range_archetype<vex::iterable::random_access_tag, int> >::value);
        }

        TEST_METHOD(is_range_is_true_for_ranges_and_false_otherwise_boost_1_55_msc_1800)
        {
#if _MSC_VER == 1800 && BOOST_VERSION == 105500
#pragma message(__FILE__ " boost::container::slist does not compile with boost 105500 and MSC 1800")
            Assert::Fail(wlog_message()
                << __FILE__
                << L" boost::container::slist does not compile with boost 105500 and MSC 1800"
                | as_string);
#else
            Assert::IsFalse(vex::iterable::is_range< boost::container::slist<int> >::value);
#endif
        }

        TEST_METHOD(stl_range_satisfies_respective_concept)
        {
            {
                typedef std::vector<int> container;  
                typedef vex::iterable::stl_interop::range_from_iterator<container::iterator> range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::RandomAccessRange<range_type>));
            }

            {
                typedef std::list<int> container;
                typedef vex::iterable::stl_interop::range_from_iterator<container::iterator> range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
            }

            {
                typedef std::map<int, int> container;
                typedef vex::iterable::stl_interop::range_from_iterator<container::iterator> range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
            }

            {
                typedef decltype(std::back_inserter(std::declval<std::vector<int>&>())) iterator;
                typedef vex::iterable::stl_interop::range_from_iterator<iterator> range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::OutputRange<range_type, int>));
            }

            {
                typedef decltype(std::ostream_iterator<int>(std::declval<std::stringstream&>())) iterator;
                typedef vex::iterable::stl_interop::range_from_iterator<iterator> range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::OutputRange<range_type, int>));
            }

#if _MSC_VER == 1800 && BOOST_VERSION == 105500
#pragma message(__FILE__ " boost::container::slist does not compile with boost 105500 and MSC 1800")
            Assert::Fail(wlog_message()
                << __FILE__
                << L" boost::container::slist does not compile with boost 105500 and MSC 1800"
                | as_string);
#else
            {
                typedef boost::container::slist<int> container;
                typedef vex::iterable::stl_interop::range_from_iterator<container::iterator> range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::ForwardRange<range_type>));
            }
#endif
        }

        TEST_METHOD(stl_range_from_vector_has_expected_traits)
        {  
            {
                 typedef std::vector<int> container;
                 typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_t;
                 typedef vex::iterable::range_traits<range_t> traits;

                 Assert::IsTrue(std::is_same<vex::iterable::random_access_tag, traits::category>::value);
                 Assert::IsTrue(std::is_same<container::value_type&, traits::reference>::value);
            }

            { // verify against boost unity...
                 typedef std::vector<int> container;
                 auto f = [](container::reference) { return true; };
                 typedef decltype(std::declval<container&>() 
                     | boost::adaptors::filtered(f)) boost_range_t;

                 Assert::IsTrue(std::is_convertible<
                     std::bidirectional_iterator_tag, 
                     boost_range_t::iterator::iterator_category
                 >::value);
                 Assert::IsTrue(std::is_same<
                     container::value_type&, 
                     boost_range_t::reference
                 >::value);
            }

            { // ref to const version
                 typedef std::vector<int> container;
                 typedef decltype(vex::iterable::make_range(std::declval<container const&>())) range_t;
                 typedef vex::iterable::range_traits<range_t> traits;

                 Assert::IsTrue(std::is_same<vex::iterable::random_access_tag, traits::category>::value);
                 Assert::IsTrue(std::is_same<container::value_type const&, traits::reference>::value);
            }

            { // verify against boost unity...
                 typedef std::vector<int> container;
                 auto f = [](container::reference) { return true; };
                 typedef decltype(std::declval<container const&>() 
                     | boost::adaptors::filtered(f)) boost_range_t;

                 Assert::IsTrue(std::is_convertible<
                     std::bidirectional_iterator_tag, 
                     boost_range_t::iterator::iterator_category
                 >::value);
                 Assert::IsTrue(std::is_same<
                     container::value_type const&, 
                     boost_range_t::reference
                 >::value);
            }

            {
                 typedef std::vector<int> container;
                 typedef container::iterator itr;
                 typedef decltype(vex::iterable::make_range(
                     std::begin(std::declval<container&>()), 
                     std::end(std::declval<container&>()))) range_t;
                 typedef vex::iterable::range_traits<range_t> traits;

                 Assert::IsTrue(std::is_same<vex::iterable::random_access_tag, traits::category>::value);
                 Assert::IsTrue(std::is_same<container::value_type&, traits::reference>::value);
            }

            { // const version
                typedef std::vector<int> container;
                 typedef container::const_iterator itr;
                 typedef decltype(vex::iterable::make_range(
                     std::begin(std::declval<container const&>()), 
                     std::end(std::declval<container const&>()))) range_t;
                 typedef vex::iterable::range_traits<range_t> traits;

                 Assert::IsTrue(std::is_same<vex::iterable::random_access_tag, traits::category>::value);
                 Assert::IsTrue(std::is_same<container::value_type const&, traits::reference>::value);
            }
        }

        TEST_METHOD(stl_range_from_array_has_expected_traits)
        {  
            {
                typedef std::array<int, 10> container;
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_t;
                typedef vex::iterable::range_traits<range_t> traits;

                Assert::IsTrue(std::is_same<vex::iterable::random_access_tag, traits::category>::value);
                Assert::IsTrue(std::is_same<container::value_type&, traits::reference>::value);
            }

            {
                typedef std::array<int, 10> container;
                typedef decltype(vex::iterable::make_range(std::declval<container const&>())) range_t;
                typedef vex::iterable::range_traits<range_t> traits;

                Assert::IsTrue(std::is_same<vex::iterable::random_access_tag, traits::category>::value);
                Assert::IsTrue(std::is_same<container::value_type const&, traits::reference>::value);
            }

            {
                typedef std::array<int, 10> container;
                typedef container::iterator itr;
                typedef decltype(vex::iterable::make_range(
                    std::begin(std::declval<container&>()), 
                    std::end(std::declval<container&>()))) range_t;
                typedef vex::iterable::range_traits<range_t> traits;

                Assert::IsTrue(std::is_same<vex::iterable::random_access_tag, traits::category>::value);
                Assert::IsTrue(std::is_same<container::value_type&, traits::reference>::value);
            }

            { // const version
                typedef std::array<int, 10> container;
                typedef decltype(vex::iterable::make_range(
                    std::begin(std::declval<container const&>()), 
                    std::end(std::declval<container const&>()))) range_t;
                typedef vex::iterable::range_traits<range_t> traits;

                Assert::IsTrue(std::is_same<vex::iterable::random_access_tag, traits::category>::value);
                Assert::IsTrue(std::is_same<container::value_type const&, traits::reference>::value);
            }
        }

        TEST_METHOD(stl_range_from_c_array_has_expected_traits)
        {  
            {
                typedef int container[10];
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_t;
                typedef vex::iterable::range_traits<range_t> traits;

                Assert::IsTrue(std::is_same<vex::iterable::random_access_tag, traits::category>::value);
                Assert::IsTrue(std::is_same<int&, traits::reference>::value);
            }

            {
                typedef const int container[10];
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_t;
                typedef vex::iterable::range_traits<range_t> traits;

                Assert::IsTrue(std::is_same<vex::iterable::random_access_tag, traits::category>::value);
                Assert::IsTrue(std::is_same<int const&, traits::reference>::value);
            }
        }

        TEST_METHOD(stl_range_from_list_has_expected_traits)
        {
            typedef std::list<int> container;
            {   
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_t;
                typedef vex::iterable::range_traits<range_t> traits;

                Assert::IsTrue(std::is_same<vex::iterable::bidirectional_tag, traits::category>::value);
                Assert::IsTrue(std::is_same<container::value_type&, traits::reference>::value);
            }

            { // const version
                typedef decltype(vex::iterable::make_range(std::declval<container const&>())) range_t;
                typedef vex::iterable::range_traits<range_t> traits;

                Assert::IsTrue(std::is_same<vex::iterable::bidirectional_tag, traits::category>::value);
                Assert::IsTrue(std::is_same<container::value_type const&, traits::reference>::value);
            }

            {   
                typedef decltype(vex::iterable::make_range(
                    std::begin(std::declval<container &>()), 
                    std::end(std::declval<container &>()))) range_t;
                typedef vex::iterable::range_traits<range_t> traits;

                Assert::IsTrue(std::is_same<vex::iterable::bidirectional_tag, traits::category>::value);
                Assert::IsTrue(std::is_same<container::value_type&, traits::reference>::value);
            }

            { // const version
                typedef decltype(vex::iterable::make_range(
                    std::begin(std::declval<container const&>()), 
                    std::end(std::declval<container const&>()))) range_t;
                typedef vex::iterable::range_traits<range_t> traits;

                Assert::IsTrue(std::is_same<vex::iterable::bidirectional_tag, traits::category>::value);
                Assert::IsTrue(std::is_same<container::value_type const&, traits::reference>::value);
            }
        }

        //TEST_METHOD(stl_range_from_map_has_expected_traits)
        //{
        //    typedef std::map<int, int> container;
        //    {   
        //        typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_t;
        //        typedef vex::iterable::range_traits<range_t> traits;

        //        Assert::IsTrue(std::is_same<vex::iterable::bidirectional_tag, traits::category>::value);
        //        Assert::IsTrue(std::is_same<container::value_type&, traits::reference>::value);
        //    }

        //    { // const version
        //        typedef decltype(vex::iterable::make_range(std::declval<container const&>())) range_t;
        //        typedef vex::iterable::range_traits<range_t> traits;

        //        Assert::IsTrue(std::is_same<vex::iterable::bidirectional_tag, traits::category>::value);
        //        Assert::IsTrue(std::is_same<container::value_type const&, traits::reference>::value);
        //    }

        //    {    
        //        typedef decltype(vex::iterable::make_range(
        //            std::begin(std::declval<container&>()), 
        //            std::end(std::declval<container&>()))) range_t;
        //        typedef vex::iterable::range_traits<range_t> traits;

        //        Assert::IsTrue(std::is_same<vex::iterable::bidirectional_tag, traits::category>::value);
        //        Assert::IsTrue(std::is_same<container::value_type&, traits::reference>::value);
        //    }

        //    { // const version
        //        typedef decltype(vex::iterable::make_range(
        //            std::begin(std::declval<container const&>()), 
        //            std::end(std::declval<container const&>()))) range_t;
        //        typedef vex::iterable::range_traits<range_t> traits;

        //        Assert::IsTrue(std::is_same<vex::iterable::bidirectional_tag, traits::category>::value);
        //        Assert::IsTrue(std::is_same<container::value_type const&, traits::reference>::value);
        //    }
        //}

        TEST_METHOD(stl_output_range_from_slist_front_inserter_has_expected_traits)
        {
#if _MSC_VER == 1800 && BOOST_VERSION == 105500
#pragma message(__FILE__ " boost::container::slist does not compile with boost 105500 and MSC 1800")
            Assert::Fail(wlog_message()
                << __FILE__
                << L" boost::container::slist does not compile with boost 105500 and MSC 1800"
                | as_string);
#else
            typedef boost::container::slist<int> container;
            typedef decltype(std::front_inserter(std::declval<container&>())) iterator;
            typedef decltype(vex::iterable::make_output_range<int>(std::declval<iterator>())) range_t;
            typedef vex::iterable::range_traits<range_t> traits;

            Assert::IsTrue(std::is_same<vex::iterable::output_tag, traits::category>::value);
            Assert::IsTrue(std::is_same<container::value_type, traits::reference>::value);
            Assert::IsTrue(std::is_same<container::value_type, traits::value_type>::value);
#endif
        }

        TEST_METHOD(stl_output_range_from_list_back_inserter_has_expected_traits)
        {
            typedef std::list<int> container;
            typedef decltype(std::back_inserter(std::declval<container&>())) iterator;
            typedef decltype(vex::iterable::make_output_range<int>(std::declval<iterator>())) range_t;
            typedef vex::iterable::range_traits<range_t> traits;

            Assert::IsTrue(std::is_same<vex::iterable::output_tag, traits::category>::value);
            Assert::IsTrue(std::is_same<container::value_type, traits::reference>::value);
            Assert::IsTrue(std::is_same<container::value_type, traits::value_type>::value);
        }

        TEST_METHOD(stl_output_range_from_list_inserter_has_expected_traits)
        {
            typedef std::list<int> container;
            container t_instance;
            typedef decltype(std::inserter(t_instance, t_instance.begin())) iterator;
            typedef decltype(vex::iterable::make_output_range<int>(std::declval<iterator>())) range_t;
            typedef vex::iterable::range_traits<range_t> traits;

            Assert::IsTrue(std::is_same<vex::iterable::output_tag, traits::category>::value);
            Assert::IsTrue(std::is_same<container::value_type, traits::reference>::value);
            Assert::IsTrue(std::is_same<container::value_type, traits::value_type>::value);
        }

        TEST_METHOD(stl_output_range_from_ostream_iterator_from_stringstream_has_expected_traits)
        {
            typedef std::stringstream container;
            container t_instance;
            typedef decltype(std::ostream_iterator<int>(t_instance)) iterator;
            typedef decltype(vex::iterable::make_output_range<int>(std::declval<iterator>())) range_t;
            typedef vex::iterable::range_traits<range_t> traits;

            Assert::IsTrue(std::is_same<vex::iterable::output_tag, traits::category>::value);
            Assert::IsTrue(std::is_same<int, traits::reference>::value);
            Assert::IsTrue(std::is_same<int, traits::value_type>::value);
        }

        template<class TItr, class TConstItr>
        void stl_range_is_constructible_from_iterator_range_impl(TItr p_beg, TItr p_end)
        {
            typedef typename std::decay<TItr>::type iterator_t;
            typedef vex::iterable::stl_interop::range_from_iterator<iterator_t> range_t;

            range_t r(p_beg, p_end);
        }

        template<class TContainer>
        void stl_range_supports_non_const_to_const_conversions_impl()
        {
            typedef typename std::decay<TContainer>::type container_t;
            typedef typename container_t::iterator iterator_t;
            typedef typename container_t::const_iterator const_iterator_t;
            typedef vex::iterable::stl_interop::range_from_iterator<iterator_t> range_t;
            typedef vex::iterable::stl_interop::range_from_iterator<const_iterator_t> const_range_t;

            const bool t_itr_supports_conversion = 
                std::is_convertible<iterator_t, const_iterator_t>::value;

            Assert::AreEqual(t_itr_supports_conversion, std::is_convertible<range_t, const_range_t>::value);

            const bool t_itr_supports_conversion_other_way_round = 
                std::is_convertible<const_iterator_t, iterator_t>::value;

            Assert::AreEqual(t_itr_supports_conversion_other_way_round, 
                std::is_convertible<const_range_t, range_t>::value);
        }

        TEST_METHOD(stl_range_from_vector_supports_non_const_to_const_conversions)
        { 
            typedef std::vector<int> container_t;
            this->stl_range_supports_non_const_to_const_conversions_impl<container_t>();
        }

        TEST_METHOD(stl_range_from_list_supports_non_const_to_const_conversions)
        { 
            typedef std::list<int> container_t;
            this->stl_range_supports_non_const_to_const_conversions_impl<container_t>();
        }

        TEST_METHOD(stl_range_from_slist_supports_non_const_to_const_conversions_boost_1_55_msc_1800)
        { 
#if _MSC_VER == 1800 && BOOST_VERSION == 105500
#pragma message(__FILE__ " boost::container::slist does not compile with boost 105500 and MSC 1800")
            Assert::Fail(wlog_message()
                << __FILE__
                << L" boost::container::slist does not compile with boost 105500 and MSC 1800"
                | as_string);
#else
            typedef boost::container::slist<int> container_t;
            this->stl_range_supports_non_const_to_const_conversions_impl<container_t>();
#endif
        }

        TEST_METHOD(stl_range_from_map_supports_non_const_to_const_conversions)
        { 
            typedef std::map<int, int> container_t;
            this->stl_range_supports_non_const_to_const_conversions_impl<container_t>();
        }

        TEST_METHOD(make_range_succeeds_for_containers)
        {
            {
                typedef std::vector<int> container;
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::RandomAccessRange<range_type>));
            }

            {
                typedef std::list<int> container;
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
            }

            {
                typedef std::map<int, int> container;
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
            }

            {
                typedef std::map<int, int> container_t;
                typedef boost::iterator_range<container_t::iterator> container;
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
            }

            {
                typedef std::map<int, int> container_t;
                typedef boost::iterator_range<container_t::iterator> container;
                typedef decltype(vex::iterable::make_range(std::declval<container const&>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
            }
        }

        TEST_METHOD(make_range_succeeds_for_containers_boost_1_55_msc_1800)
        {
#if _MSC_VER == 1800 && BOOST_VERSION == 105500
#pragma message(__FILE__ " boost::container::slist does not compile with boost 105500 and MSC 1800")
            Assert::Fail(wlog_message()
                << __FILE__
                << L" boost::container::slist does not compile with boost 105500 and MSC 1800"
                | as_string);
#else
            {
                typedef boost::container::slist<int> container;
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::ForwardRange<range_type>));
            }
#endif
        }

        TEST_METHOD(make_range_succeeds_for_iterator_ranges)
        {   
            {
                typedef std::vector<int> container; 
                typedef container::iterator itr;
                typedef decltype(vex::iterable::make_range(std::declval<itr>(), std::declval<itr>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::RandomAccessRange<range_type>));
                Assert::IsTrue(std::is_same<int&, range_type::reference>::value);
            }

            {
                typedef std::list<int> container;
                typedef container::iterator itr;
                typedef decltype(vex::iterable::make_range(std::declval<itr>(), std::declval<itr>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
                Assert::IsTrue(std::is_same<int&, range_type::reference>::value);
            }

            {
                typedef std::map<int, int> container;
                typedef container::iterator itr;
                typedef decltype(vex::iterable::make_range(std::declval<itr>(), std::declval<itr>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
                Assert::IsTrue(std::is_same<container::reference, range_type::reference>::value);
            }

            {
                typedef std::map<int, int> container;
                typedef container::const_iterator itr;
                typedef decltype(vex::iterable::make_range(std::declval<itr>(), std::declval<itr>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
                Assert::IsTrue(std::is_same<container::value_type const&, range_type::reference>::value);
            }

            {
                typedef std::map<int, int> container_t;
                typedef boost::iterator_range<container_t::iterator> container;
                typedef container::iterator itr;
                typedef decltype(vex::iterable::make_range(std::declval<itr>(), std::declval<itr>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
                Assert::IsTrue(std::is_same<container::value_type&, range_type::reference>::value);
                Assert::IsTrue(std::is_same<container::reference, range_type::reference>::value);
            }

            {
                typedef std::map<int, int> container_t;
                typedef decltype(std::declval<container_t&>() | boost::adaptors::map_keys) boost_range_t;
                typedef decltype(vex::iterable::make_range(std::declval<boost_range_t>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::BiDirectionalRange<range_type>));
                Assert::IsTrue(std::is_same<boost_range_t::value_type const &, range_type::reference>::value);
                Assert::IsTrue(std::is_same<boost_range_t::reference, range_type::reference>::value);
            }

#if _MSC_VER == 1800 && BOOST_VERSION == 105500
#pragma message(__FILE__ " boost::container::slist does not compile with boost 105500 and MSC 1800")
            Assert::Fail(wlog_message()
                << __FILE__
                << L" boost::container::slist does not compile with boost 105500 and MSC 1800"
                | as_string);
#else
            {
                typedef boost::container::slist<int> container;
                typedef container::iterator itr;
                typedef decltype(vex::iterable::make_range(std::declval<itr>(), std::declval<itr>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::ForwardRange<range_type>));
                Assert::IsTrue(std::is_same<int&, range_type::reference>::value);
            }
#endif
        }


        TEST_METHOD(make_range_succeeds_for_compile_time_c_arrays)
        {
            {
                typedef int container[10];
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::RandomAccessRange<range_type>));
                Assert::IsTrue(std::is_same<int&, range_type::reference>::value);
            }

            {
                typedef const int container[10];
                typedef decltype(vex::iterable::make_range(std::declval<container&>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::RandomAccessRange<range_type>));
                Assert::IsTrue(std::is_same<int const&, range_type::reference>::value);
            }
        }

        TEST_METHOD(make_range_succeeds_for_output_iterators)
        {
            {
                typedef decltype(std::back_inserter(std::declval<std::vector<int>&>())) iterator;
                typedef decltype(vex::iterable::make_output_range<int>(std::declval<iterator>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::OutputRange<range_type, int>));
            }

            {
                typedef decltype(std::ostream_iterator<int>(std::declval<std::stringstream&>())) iterator;
                typedef decltype(vex::iterable::make_output_range<char>(std::declval<iterator>())) range_type;
                BOOST_CONCEPT_ASSERT((vex::iterable::concept::OutputRange<range_type, char>));
            }
        }

        class fake_type {};

        TEST_METHOD(make_range_does_not_succeed_for_invalid_types)
        {
            //{
            //    typedef int invalid_type;
            //    typedef decltype(vex::iterable::make_range(std::declval<invalid_type>())) range_type;
            //    Assert::IsTrue(std::is_same<void, range_type>::value);
            //}

            //{
            //    typedef int& invalid_type;
            //    typedef decltype(vex::iterable::make_range(std::declval<invalid_type>())) range_type;
            //    Assert::IsTrue(std::is_same<void, range_type>::value);
            //    //int p; vex::iterable::make_range(p);
            //}

            //{
            //    typedef int* invalid_type;
            //    typedef decltype(vex::iterable::make_range(std::declval<invalid_type>())) range_type;
            //    Assert::IsTrue(std::is_same<void, range_type>::value);
            //    //int p; vex::iterable::make_range(&p);
            //}

            //{
            //    typedef fake_type invalid_type;
            //    typedef decltype(vex::iterable::make_range(std::declval<invalid_type>())) range_type;
            //    Assert::IsTrue(std::is_same<void, range_type>::value);
            //    //vex::iterable::make_range(fake_type());
            //}
        }
    };
}}